package com.xuecheng.manage_cms.service.impl;

import com.alibaba.fastjson.JSON;
import com.mongodb.client.gridfs.GridFSBucket;
import com.mongodb.client.gridfs.GridFSDownloadStream;
import com.mongodb.client.gridfs.model.GridFSFile;
import com.xuecheng.framework.domain.cms.CmsConfig;
import com.xuecheng.framework.domain.cms.CmsPage;
import com.xuecheng.framework.domain.cms.CmsTemplate;
import com.xuecheng.framework.domain.cms.response.CmsCode;
import com.xuecheng.framework.domain.cms.response.CmsPageResult;
import com.xuecheng.framework.exception.CustomException;
import com.xuecheng.framework.exception.CustomExcetionCast;
import com.xuecheng.framework.model.response.ResponseResult;
import com.xuecheng.framework.model.response.ResultCode;
import com.xuecheng.manage_cms.config.RabbitConfigPro;
import com.xuecheng.manage_cms.dao.CmsConfigRepository;
import com.xuecheng.manage_cms.dao.CmsPageRepository;
import com.xuecheng.manage_cms.dao.CmsTemplateRepository;
import com.xuecheng.manage_cms.service.CmsConfigService;
import freemarker.cache.StringTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import org.apache.commons.io.IOUtils;
import org.bson.types.ObjectId;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.gridfs.GridFsResource;
import org.springframework.data.mongodb.gridfs.GridFsTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

@Service
public class CmsConfigServiceImpl implements CmsConfigService {
    @Autowired
    GridFsTemplate gridFsTemplate;
    @Autowired
    RabbitTemplate rabbitTemplate;

    @Autowired
    GridFSBucket gridFSBucket;
    @Autowired
    RestTemplate restTemplate;
    @Autowired
    private CmsConfigRepository cmsConfigRepository;
    @Autowired
    private CmsPageRepository cmsPageRepository;
    @Autowired
    private CmsTemplateRepository cmsTemplateRepository;

    @Override
    public CmsConfig find(String id) {
        Optional<CmsConfig> cmsConfig = cmsConfigRepository.findById(id);
        if (cmsConfig.isPresent()) {
            CmsConfig config = cmsConfig.get();
            return config;
        }
        return null;
    }

    /**
     * @Description: 页面静态化
     * @Param:  id
     * @return: HTML字符串
     * @Author: Mr.Yuan
     * @Date:
     */
    @Override
    public String getHtml(String pageId) {
//        通过页面id找到页面对象，获取dataUrl
        Optional<CmsPage> cmsPage = cmsPageRepository.findById(pageId);
        if (!cmsPage.isPresent()) {
            throw new CustomException(CmsCode.CMS_PGAE_NOEXIST);
        }
        CmsPage cmsPage1 = cmsPage.get();
        String dataUrl = cmsPage1.getDataUrl();
        String templateId = cmsPage1.getTemplateId();

//        通过dataUrl远程调用找到页面模型数据
        Map map = this.getCmsConfig(dataUrl);

//        找到页面模板
        Optional<CmsTemplate> templateOptional = cmsTemplateRepository.findById(templateId);
        if (!templateOptional.isPresent()) {
            throw new CustomException(CmsCode.CMS_GENERATEHTML_TEMPLATEISNULL);
        }
        CmsTemplate template1 = templateOptional.get();
        String fileId = template1.getTemplateFileId();
        //        根据文件id从数据库中找到数据
        GridFSFile one = gridFsTemplate.findOne(Query.query(Criteria.where("_id").is(fileId)));
        if (StringUtils.isEmpty(one)) {
            throw new CustomException(CmsCode.CMS_GENERATEHTML_TEMPLATEISNULL);
        }
//        打开一个输入流
        GridFSDownloadStream gridFSDownloadStream = gridFSBucket.openDownloadStream(one.getObjectId());
//          创建gridFsResource对象，用于截取输入流
        GridFsResource gridFsResource = new GridFsResource(one, gridFSDownloadStream);
//        读取流,转成字符串
        String content;
        try {
            content = IOUtils.toString(gridFSDownloadStream, "utf-8");
        } catch (IOException e) {
            throw new CustomException(CmsCode.CMS_GENERATEHTML_TEMPLATEISNULL);
        }


//        进行静态化
//        创建配置类
        Configuration configuration = new Configuration(Configuration.getVersion());

        StringTemplateLoader stringTemplateLoader = new StringTemplateLoader();
        stringTemplateLoader.putTemplate("template", content);
        configuration.setTemplateLoader(stringTemplateLoader);
        Template template = null;
        String templateHtml = null;
        try {
            template = configuration.getTemplate("template", "utf-8");
            templateHtml = FreeMarkerTemplateUtils.processTemplateIntoString(template, map);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (TemplateException e) {
            e.printStackTrace();
        }
        return templateHtml;
    }

    private Map getCmsConfig(String dataUrl) {
        ResponseEntity<Map> entity = restTemplate.getForEntity(dataUrl, Map.class);
        Map body = entity.getBody();
        return body;
    }

    //    页面静态化存入数据库，生产者将信息存入RabbitMQ中，通知消费端
    @Override
    public ResponseResult publishHtml(String pageId) {
//        根据pageId查找页面，进行静态化，将得到静态化页面
        String html = this.getHtml(pageId);
//        将静态化的页面存入Gridfile中，
        if (StringUtils.isEmpty(html)) {
            throw CustomExcetionCast.getCusException(CmsCode.CMS_GENERATEHTML_HTMLISNULL);
        }
        CmsPage cmsPage = this.storeHtml(pageId, html);
        System.out.println(cmsPage.getHtmlFileId());
//        静态化后的页面id发送给RabbitMQ，通知消费端
        this.producer(pageId);
        return ResponseResult.SUCCESS();
    }

   public CmsPage storeHtml(String pageId, String html) {
//        查找页面，获取页面信息
        Optional<CmsPage> pageOptional = cmsPageRepository.findById(pageId);
        if (!pageOptional.isPresent()) {
            throw CustomExcetionCast.getCusException(CmsCode.CMS_PGAE_NOEXIST);
        }
        CmsPage cmsPage = pageOptional.get();
        String pageName = cmsPage.getPageName();
//        将字符串转化成流
        InputStream inputStream = null;
        try {
            inputStream = IOUtils.toInputStream(html, "utf-8");
        } catch (IOException e) {
            e.printStackTrace();
        }
        ObjectId objectId = gridFsTemplate.store(inputStream, cmsPage.getPageName());
        cmsPage.setHtmlFileId(objectId.toString());
        CmsPage save = cmsPageRepository.save(cmsPage);
        return save;
    }

    //      将消息存入RabbitMQ存入消息队列
    public void producer(String pageId) {
        Optional<CmsPage> pageOptional = cmsPageRepository.findById(pageId);
        if (!pageOptional.isPresent()) {
            throw CustomExcetionCast.getCusException(CmsCode.CMS_PGAE_NOEXIST);
        }
        CmsPage cmsPage = pageOptional.get();
        String siteId = cmsPage.getSiteId();
        Map map = new HashMap();
        map.put("pageId", pageId);

        String jsonString = JSON.toJSONString(map);
        rabbitTemplate.convertAndSend(RabbitConfigPro.EX_ROUTING_CMS_POSTPAGE, siteId, jsonString);
    }
}
